package com.totem.product.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.totem.base.constants.CommonConstants;
import com.totem.base.constants.ErrorCode;
import com.totem.base.enums.SwitchEnum;
import com.totem.base.enums.YesNoEnum;
import com.totem.base.exception.BaseException;
import com.totem.base.mybatis.UserIdContext;
import com.totem.base.util.DateUtils;
import com.totem.customer.mapper.TCustomerMapper;
import com.totem.customer.mapper.TFavoritesMapper;
import com.totem.customer.model.TCustomers;
import com.totem.customer.model.TFavorites;
import com.totem.product.mapper.*;
import com.totem.product.model.*;
import com.totem.product.service.ProductCommonService;
import com.totem.product.vo.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

@Slf4j
@Service
public class ProductCommonServiceImpl implements ProductCommonService {
    @Autowired
    private TCustomerMapper tCustomerMapper;
    @Autowired
    private TProductMapper tProductMapper;
    @Autowired
    private TProductUrlMapper tProductUrlMapper;
    @Autowired
    private TProductSpecMapper tProductSpecMapper;
    @Autowired
    private TProductDetailMapper tProductDetailMapper;
    @Autowired
    private TProductInvMapper tProductInvMapper;
    @Autowired
    private TFavoritesMapper tFavoritesMapper;
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    @Override
    public List<ProductVO> list(List<Long> productIdList) {
        Long customerId = UserIdContext.getUserId();
        if(customerId==null){
            throw new BaseException(ErrorCode.UNAUTHORIZED);
        }

        LambdaQueryWrapper<TProducts> productsQuery = new LambdaQueryWrapper<>();
        productsQuery.in(TProducts::getId, productIdList);
        List<TProducts> productList = tProductMapper.selectList(productsQuery);
        Map<Long, TProducts> productsMap = productList.stream().collect(Collectors.toMap(TProducts::getId, Function.identity()));
        List<Long> custIds = productList.stream().map(TProducts::getCreateBy).toList();

        LambdaQueryWrapper<TCustomers> custQuery = new LambdaQueryWrapper<>();
        custQuery.in(TCustomers::getId, custIds);
        List<TCustomers> custList = tCustomerMapper.selectList(custQuery);
        Map<Long, String> custNameMap = custList.stream().collect(Collectors.toMap(TCustomers::getId, TCustomers::getNickname));

        LambdaQueryWrapper<TProductUrl> productUrlQuery = new LambdaQueryWrapper<>();
        productUrlQuery.in(TProductUrl::getProductId, productIdList);
        List<TProductUrl> productUrlList = tProductUrlMapper.selectList(productUrlQuery);
        Map<Long, TProductUrl> productUrlMap = productUrlList.stream().collect(Collectors.toMap(TProductUrl::getProductId, Function.identity()));

        List<TProductSpec> latestSpecList = tProductSpecMapper.selectLatestSpec(productIdList);
        Map<Long, TProductSpec> latestProductSpecMap = latestSpecList.stream().collect(Collectors.toMap(TProductSpec::getProductId, Function.identity()));

        LambdaQueryWrapper<TProductSpec> specQuery = new LambdaQueryWrapper<>();
        specQuery.in(TProductSpec::getProductId, productIdList);
        List<TProductSpec> productSpecList = tProductSpecMapper.selectList(specQuery);
        Map<Long, List<TProductSpec>> productSpecListMap = productSpecList.stream().collect(Collectors.groupingBy(TProductSpec::getProductId));


        LambdaQueryWrapper<TProductDetail> productDetailQuery = new LambdaQueryWrapper<>();
        productDetailQuery.in(TProductDetail::getProductId, productIdList);
        List<TProductDetail> productDetailList = tProductDetailMapper.selectList(productDetailQuery);
        Map<Long, TProductDetail> productDetailMap = productDetailList.stream().collect(Collectors.toMap(TProductDetail::getProductId, Function.identity()));

        LambdaQueryWrapper<TProductInv> invQuery = new LambdaQueryWrapper<>();
        invQuery.in(TProductInv::getProductId, productIdList);
        List<TProductInv> productInvList = tProductInvMapper.selectList(invQuery);
        Map<Long, TProductInv> productInvMap = productInvList.stream().collect(Collectors.toMap(TProductInv::getProductId, Function.identity()));

        LambdaQueryWrapper<TFavorites> favoritQuery = new LambdaQueryWrapper<>();
        favoritQuery.eq(TFavorites::getCustomerId, customerId);
        List<TFavorites> tFavoritesList = tFavoritesMapper.selectList(favoritQuery);
        List<Long> favoriteProductIdList = tFavoritesList.stream().map(TFavorites::getProductId).toList();

        List<ProductVO> productVOList = productIdList.stream().map(id->{
            ProductVO productVO = new ProductVO();
            ProductSpecVO latestProductSpecVO = new ProductSpecVO();

            TProducts tProducts = productsMap.get(id);
            TProductUrl tProductUrl = productUrlMap.get(id);
            TProductSpec latestProductSpec = latestProductSpecMap.get(id);
            List<TProductSpec> specList = productSpecListMap.get(id);
            TProductDetail tProductDetail = productDetailMap.get(id);
            TProductInv tProductInv = productInvMap.get(id);
            String nickname = custNameMap.get(tProducts.getCreateBy());
            boolean isFavorite = !CollectionUtils.isEmpty(favoriteProductIdList) && favoriteProductIdList.contains(id);

            productVO.setFavoriteState(isFavorite);
            productVO.setProductId(tProducts.getId());
            productVO.setProductName(tProducts.getProductName());
            productVO.setIntroductory(tProducts.getIntroductory());

            BeanUtils.copyProperties(latestProductSpec, latestProductSpecVO);
            productVO.setLatestProductSpecVO(latestProductSpecVO);

            if(!CollectionUtils.isEmpty(specList)){
                List<ProductSpecVO> sepcVoList = specList.stream().map(spec->{
                    ProductSpecVO specVo = new ProductSpecVO();
                    BeanUtils.copyProperties(spec, specVo);
                    return specVo;
                }).toList();
                productVO.setProductSpecVOList(sepcVoList);
            }

            ProductUrlVO urlVO = new ProductUrlVO();
            BeanUtils.copyProperties(tProductUrl, urlVO);
            productVO.setProductUrlVO(urlVO);
            String carouselUrls = tProductUrl.getCarouselUrls();
            if(StringUtils.isNotBlank(carouselUrls)){
                urlVO.setCarouselUrls(Arrays.asList(carouselUrls.split(",")));
            }

            ProductInvVO invVO = new ProductInvVO();
            BeanUtils.copyProperties(tProductInv, invVO);
            productVO.setProductInvVO(invVO);

            productVO.setCreateByNickname(nickname);

            Date updateTime = tProducts.getUpdateTime();
            String createAt = DateUtils.formatDate(updateTime, CommonConstants.DEFAULT_DATETIME_FORMAT);
            productVO.setCreateAt(createAt);

            ProductDetailVO productDetailVO = new ProductDetailVO();
            BeanUtils.copyProperties(tProductDetail, productDetailVO);
            productVO.setProductDetailVO(productDetailVO);
            return productVO;
        }).collect(Collectors.toList());

        return productVOList;
    }

    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    @Override
    public List<ProductVO> list(ProductPageVO vo) {
        Long customerId = UserIdContext.getUserId();
        if(customerId==null){
            throw new BaseException(ErrorCode.UNAUTHORIZED);
        }

        Long current = vo.getCurrent();
        if(current==null){
            current=0l;
        }
        Long pageSize = vo.getPageSize();
        if(pageSize==null){
            pageSize=0l;
        }

        Page<TProducts> page = new Page<>();
        page.setCurrent(current);
        page.setSize(pageSize);

        String shelfState = vo.getShelfState();
        String searchWord = vo.getSearchWord();

        LambdaQueryWrapper<TProductInv> invQuery = new LambdaQueryWrapper<>();
        invQuery.in(TProductInv::getShelfState, shelfState);
        List<TProductInv> productInvList = tProductInvMapper.selectList(invQuery);
        Map<Long, TProductInv> productInvMap = productInvList.stream().collect(Collectors.toMap(TProductInv::getProductId, Function.identity()));
        List<Long> productIdList = productInvList.stream().map(TProductInv::getProductId).toList();
        if(CollectionUtils.isEmpty(productIdList)){
            log.warn("上下架状态为[{}]的产品不存在", shelfState);
            return List.of();
        }

        LambdaQueryWrapper<TProductDetail> detailQuery = new LambdaQueryWrapper<>();
        detailQuery.eq(StringUtils.isNotBlank(vo.getRecommend()), TProductDetail::getRecommend, vo.getRecommend());
        detailQuery.in(TProductDetail::getProductId, productIdList);
        List<TProductDetail> productDetailList = tProductDetailMapper.selectList(detailQuery);
        if(CollectionUtils.isEmpty(productDetailList)){
            log.warn("推荐的产品不存在");
            return List.of();
        }
        Map<Long, TProductDetail> productDetailMap = productDetailList.stream().collect(Collectors.toMap(TProductDetail::getProductId, Function.identity()));
        productIdList = productDetailList.stream().map(TProductDetail::getProductId).toList();

        LambdaQueryWrapper<TProducts> productsQuery = new LambdaQueryWrapper<>();
        productsQuery.in(TProducts::getId, productIdList);
        productsQuery.like(StringUtils.isNotBlank(searchWord), TProducts::getProductName, searchWord);
        productsQuery.orderByDesc(TProducts::getUpdateTime);
        List<TProducts> productList = null;
        long count = 0;
        if(current==0 || pageSize==0){
            productList = tProductMapper.selectList(productsQuery);
            count = productList.size();
        }else {
            productList = tProductMapper.selectPage(page, productsQuery).getRecords();
            count = page.getTotal();
        }
        if (CollectionUtils.isEmpty(productList)) {
            log.warn("关键字为[{}]的产品不存在", searchWord);
            return List.of();
        }
        Map<Long, TProducts> productsMap = productList.stream().collect(Collectors.toMap(TProducts::getId, Function.identity()));
        productIdList = productList.stream().map(TProducts::getId).toList();
        List<Long> custIds = productList.stream().map(TProducts::getCreateBy).toList();

        LambdaQueryWrapper<TCustomers> custQuery = new LambdaQueryWrapper<>();
        custQuery.in(TCustomers::getId, custIds);
        List<TCustomers> custList = tCustomerMapper.selectList(custQuery);
        Map<Long, String> custNameMap = custList.stream().collect(Collectors.toMap(TCustomers::getId, TCustomers::getNickname));

        LambdaQueryWrapper<TProductUrl> productUrlQuery = new LambdaQueryWrapper<>();
        productUrlQuery.in(TProductUrl::getProductId, productIdList);
        List<TProductUrl> productUrlList = tProductUrlMapper.selectList(productUrlQuery);
        Map<Long, TProductUrl> productUrlMap = productUrlList.stream().collect(Collectors.toMap(TProductUrl::getProductId, Function.identity()));

        List<TProductSpec> latestSpecList = tProductSpecMapper.selectLatestSpec(productIdList);
        Map<Long, TProductSpec> latestProductSpecMap = latestSpecList.stream().collect(Collectors.toMap(TProductSpec::getProductId, Function.identity()));

        LambdaQueryWrapper<TProductSpec> specQuery = new LambdaQueryWrapper<>();
        specQuery.in(TProductSpec::getProductId, productIdList);
        List<TProductSpec> productSpecList = tProductSpecMapper.selectList(specQuery);
        Map<Long, List<TProductSpec>> productSpecListMap = productSpecList.stream().collect(Collectors.groupingBy(TProductSpec::getProductId));

        LambdaQueryWrapper<TFavorites> favoritQuery = new LambdaQueryWrapper<>();
        favoritQuery.eq(TFavorites::getCustomerId, customerId);
        List<TFavorites> tFavoritesList = tFavoritesMapper.selectList(favoritQuery);
        List<Long> favoriteProductIdList = tFavoritesList.stream().map(TFavorites::getProductId).toList();

        List<ProductVO> productVOList = productIdList.stream().map(id->{
            ProductVO productVO = new ProductVO();
            ProductSpecVO latestProductSpecVO = new ProductSpecVO();

            TProductInv tProductInv = productInvMap.get(id);
            TProducts tProducts = productsMap.get(id);

            TProductUrl tProductUrl = productUrlMap.get(id);
            TProductSpec latestProductSpec = latestProductSpecMap.get(id);
            List<TProductSpec> specList = productSpecListMap.get(id);
            TProductDetail tProductDetail = productDetailMap.get(id);

            String nickname = custNameMap.get(id);
            boolean isFavorite = !CollectionUtils.isEmpty(favoriteProductIdList) && favoriteProductIdList.contains(id);

            productVO.setFavoriteState(isFavorite);

            ProductInvVO invVO = new ProductInvVO();
            BeanUtils.copyProperties(tProductInv, invVO);
            int inv = tProductInv.getInv();
            int usable = tProductInv.getUsable();
            int freeze = tProductInv.getFreeze();
            int salesVol = inv-usable-freeze;
            invVO.setSalesVol(salesVol);
            productVO.setProductInvVO(invVO);


            productVO.setProductId(tProducts.getId());
            productVO.setProductName(tProducts.getProductName());
            productVO.setIntroductory(tProducts.getIntroductory());

            BeanUtils.copyProperties(latestProductSpec, latestProductSpecVO);
            productVO.setLatestProductSpecVO(latestProductSpecVO);

            if(!CollectionUtils.isEmpty(specList)){
                List<ProductSpecVO> sepcVoList = specList.stream().map(spec->{
                    ProductSpecVO specVo = new ProductSpecVO();
                    BeanUtils.copyProperties(spec, specVo);
                    return specVo;
                }).toList();
                productVO.setProductSpecVOList(sepcVoList);
            }

            ProductUrlVO urlVO = new ProductUrlVO();
            BeanUtils.copyProperties(tProductUrl, urlVO);
            productVO.setProductUrlVO(urlVO);
            String carouselUrls = tProductUrl.getCarouselUrls();
            if(StringUtils.isNotBlank(carouselUrls)){
                urlVO.setCarouselUrls(Arrays.asList(carouselUrls.split(",")));
            }

            productVO.setCreateByNickname(nickname);

            Date updateDate = tProducts.getUpdateTime();
            String createAt = DateUtils.formatDate(updateDate, CommonConstants.DEFAULT_DATETIME_FORMAT);
            productVO.setCreateAt(createAt);

            ProductDetailVO productDetailVO = new ProductDetailVO();
            BeanUtils.copyProperties(tProductDetail, productDetailVO);
            productVO.setProductDetailVO(productDetailVO);
            return productVO;
        }).collect(Collectors.toList());

        vo.setTotal(count);
        return productVOList;
    }
}
